package net.xt.myupload.controller;

import net.xt.myupload.service.FileDownloader;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;

@RestController
public class FileDownloadController {

    @Resource
    private FileDownloader fileDownloader;

    // 大文件断点下载，客户端方法
    @PostMapping("/testBreakDownload")
    public ResponseEntity<String> testBreakDownload() {
        try {
            this.fileDownloader.downloadFile(
                    "http://localhost:8080/breakDownload",
                    "测试.mp4"
            );
            return ResponseEntity.ok("下载完成");
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.internalServerError().body(e.getMessage());
        }
    }

    // 大文件断点下载，服务端方法
    @PostMapping("/breakDownload")
    public void breakDownload(HttpServletRequest request,
                              HttpServletResponse response,
                              String fileName) {
        InputStream inputStream = null;
        ServletOutputStream outputStream = null;

        try {
            File file = new File("D:/Download/" + fileName);
            long fSize = file.length();

            response.setCharacterEncoding("utf-8");
            response.setContentType("application/x-download");
            response.setHeader("Accept-Ranges", "bytes");
            // 文件名中文乱码，这里服务器端加密，客户端调用时需要解密
            String resultFileName = URLEncoder.encode(fileName, "utf-8");
            response.setHeader("Content-Disposition",
                    "attachment;fileName=" + resultFileName
            );
            response.setHeader("fName", resultFileName);

            long start = 0, end = 0, contentLength = 0;
            if (null != request.getHeader("Range")) {
                // 分片下载
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);

                try {
                    // 获取分片的开始、结束位置
                    String range = request.getHeader("Range")
                            .replaceAll("bytes=", "");
                    String[] ranges = range.split("-");
                    if (ranges.length == 2) {
                        start = Long.valueOf(ranges[0].trim());
                        end = Long.valueOf(ranges[1].trim());

                        // 最后一个分片，结束位置就是文件的大小
                        if (end > fSize - 1) {
                            end = fSize - 1;
                        }
                    } else {
                        start = Long.valueOf(range.replaceAll("-", ""));
                    }
                    // 每个分片的大小
                    contentLength = end - start + 1;

                    // 设置 Content-Length和 Content-Range
                    response.setHeader("Content-Length", String.valueOf(contentLength));
                    response.setHeader("Content-Range", new StringBuffer("bytes ")
                            .append(start + "").append("-")
                            .append((fSize - 1) + "")
                            .append("/")
                            .append(fSize + "")
                            .toString());

                    // 读取每个文件分片，输出到客户端
                    inputStream = new FileInputStream("D:/Download/" + fileName);
                    inputStream.skip(start);
                    outputStream = response.getOutputStream();
                    byte[] buffer = new byte[1024];
                    int length = 0, sum = 0;
                    while (sum < contentLength) {
                        if (contentLength - sum <= buffer.length) {
                            length = inputStream.read(buffer, 0, (int) contentLength - sum);
                        } else {
                            length = inputStream.read(buffer, 0, buffer.length);
                        }
                        sum = sum + length;
                        outputStream.write(buffer, 0, length);
                    }
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                    start = 0;
                }
            } else {
                // 全文件下载
                response.setStatus(HttpServletResponse.SC_OK);
                // 设置 Content-Length
                response.setHeader("Content-Length", String.valueOf(fSize));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != outputStream)
                    outputStream.flush();
                if (null != outputStream)
                    outputStream.close();
                if (null != inputStream)
                    inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
